package other.edan.erp.k3;


import com.alibaba.fastjson.JSONObject;
import com.rkhd.platform.sdk.ScheduleJob;
import com.rkhd.platform.sdk.api.annotations.RequestMethod;
import com.rkhd.platform.sdk.api.annotations.RestApi;
import com.rkhd.platform.sdk.api.annotations.RestMapping;
import com.rkhd.platform.sdk.api.annotations.RestQueryParam;
import com.rkhd.platform.sdk.data.model.*;
import com.rkhd.platform.sdk.exception.ApiEntityServiceException;
import com.rkhd.platform.sdk.exception.AsyncTaskException;
import com.rkhd.platform.sdk.exception.ScriptBusinessException;
import com.rkhd.platform.sdk.log.Logger;
import com.rkhd.platform.sdk.log.LoggerFactory;
import com.rkhd.platform.sdk.model.OperateResult;
import com.rkhd.platform.sdk.param.ScheduleJobParam;
import com.rkhd.platform.sdk.service.FutureTaskService;
import com.rkhd.platform.sdk.service.XoqlService;
import com.rkhd.platform.sdk.task.FutureTask;
import org.apache.commons.lang.StringUtils;
import other.edan.erp.apitool.EdanK3Utils;
import other.edan.erp.utils.*;

import java.util.*;
import java.util.stream.Collectors;


/**
 * @Description 同步K3销售出库数据
 * @Author 黎炎松
 * 2024-08-30 10:20
 */
@RestApi(baseUrl = "/edan/salesOut")
public class SyncSaleOut extends SyncSuper implements ScheduleJob, FutureTask {
    private static XoqlService xoqlService = XoqlService.instance();
    private static final Logger LOGGER = LoggerFactory.getLogger();
    private static String LOGGER_MSG = "同步K3销售出库数据 ==> ";

    // 执行定时任务
    @Override
    public void execute(ScheduleJobParam scheduleJobParam) {
        LOGGER.debug(LOGGER_MSG + " 执行定时任务开始");
        try {
            String messageId = FutureTaskService.instance().addFutureTask(getClass(), "");
            LOGGER.info(LOGGER_MSG + "异步ID:" + messageId);
        } catch (Exception e) {
            LOGGER.error(LOGGER_MSG + " ----- 发生异常：" + e.getMessage());
        }
    }

    // 执行异步函数
    @Override
    public void execute(String s) throws ScriptBusinessException {
        if (StringUtils.isNotBlank(s)) {
            String[] split = s.split(",");
            startSyncSaleOut(1,"", split[0], split[1]);
        } else {
            startSyncSaleOut(2,"", "", "");
        }
    }

    /**
     * 手动触发出库同步
     * @param
     * @return
     */
    @RestMapping(value = "/handerSync", method = RequestMethod.POST)
    public ResultVo handerSync() throws AsyncTaskException {
        LOGGER.debug("手动触发同步");
        String messageId = FutureTaskService.instance().addFutureTask(getClass(), "");
        LOGGER.info(LOGGER_MSG + "异步ID:" + messageId);
        return ResultVo.success("开始同步");
    }

    /**
     * 手动触发出库同步 （当前数据）
     * @param
     * @return
     */
    @RestMapping(value = "/syncById", method = RequestMethod.POST)
    public ResultVo syncById(@RestQueryParam(name = "id") Long outId, @RestQueryParam(name = "icstockbillNo") String icstockbillNo) {

        LOGGER.debug("根据编号手动触发同步: icstockbillNo " + icstockbillNo);
        if (StringUtils.isNotBlank(icstockbillNo)) {
            return startSyncSaleOut(1, icstockbillNo, "", "");
        }

        // 获取编码
        LOGGER.debug("根据编号手动触发同步: outId " + outId);
        SalesOutReceipt__c salesOutReceipt = new SalesOutReceipt__c();
        salesOutReceipt.setId(outId);
        salesOutReceipt = HCXObjectService.get(salesOutReceipt);
        String outNo = salesOutReceipt.getName();

        LOGGER.debug("根据编号手动触发同步: " + outNo);
        return startSyncSaleOut(1, outNo, "", "");
    }

    /**
     * 手动触发计算【出库明细】成本价格 （博识成本明细表 中获取）
     * @param
     * @return
     */
    @RestMapping(value = "/calcCostPrice", method = RequestMethod.POST)
    public ResultVo calcCostPrice(@RestQueryParam(name = "detailId") Long detailId) {

        try {
            // 获取出库明细数据
            LOGGER.debug("手动触发计算出库明细中的成本字段: " + detailId);
            SalesOutReceiptDetails__c salesOutReceiptDetails = new SalesOutReceiptDetails__c();
            salesOutReceiptDetails.setId(detailId);
            salesOutReceiptDetails = HCXObjectService.get(salesOutReceiptDetails);


            // 根据产品从【博识成本明细表】模块获取近一年的成本
            Long porductId = salesOutReceiptDetails.getPorductName__c();
            if (porductId == null) {
                return ResultVo.error("关联产品为空~");
            }
            long endTimeLong = System.currentTimeMillis();
            long startTimeLong = HCDateUtils.addDaysToLong(endTimeLong, -365);
            String sql = String.format("select productName__c, sum(totalCost__c) / sum(quantity__c) as avg  from costDetail__c " +
                    " where productName__c.proxyProducts__c = 16 and productName__c in (%s) and date__c between %s and %s group by productName__c ", porductId, startTimeLong, endTimeLong);
            Map<Long, Double> crmCostMap = xoqlService.query(sql).getRecords().stream().collect(Collectors.toMap(e -> e.getLong("productName__c"), e1 -> e1.getDouble("avg"), (e, e1) -> e));

            // 赋值
            SalesOutReceiptDetails__c upDetail = new SalesOutReceiptDetails__c();
            upDetail.setId(detailId);
            Double costUnitPrice = crmCostMap.get(porductId);
            int costAttr = 1; // 成本归属 1：理邦  2：博识
            if (costUnitPrice != null) {
                costAttr = 2;
            }
            upDetail.setNoTaxCostUnitPrice__c(costUnitPrice);
            upDetail.setCostAttribution__c(costAttr);
            HCXObjectService.update(upDetail);
            LOGGER.info("处理成功");

            return ResultVo.success("处理成功");
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("处理异常: " + e.getMessage());
            return ResultVo.error("处理异常");
        }
    }

    /**
     * 手动触发同步出库数据
     * @param
     * @return
     */
    @RestMapping(value = "/handByDate", method = RequestMethod.GET)
    public ResultVo handByDate(@RestQueryParam(name = "startDate") String startDate, @RestQueryParam(name = "endDate") String endDate) throws AsyncTaskException {
        LOGGER.debug(LOGGER_MSG + "手动触发同步出库数据 startDate = " + startDate);
        if (StringUtils.isBlank(startDate) || StringUtils.isBlank(endDate)) {
            return ResultVo.error("同步日期不可为空");
        }
        //startSyncSaleOut(1,"", "2025-01-09 23:59:59", "2025-01-10 23:59:59");
        String messageId = FutureTaskService.instance().addFutureTask(getClass(), startDate + "," + endDate);
        LOGGER.info(LOGGER_MSG + "异步ID:" + messageId);
        return ResultVo.success("开始同步");
    }

    public static void main(String[] args)  {
        HCXObjectService.isLocal = true;
        SyncSaleOut syncSaleOut = new SyncSaleOut();
        // XOUT463994 XOUT463995
        syncSaleOut.startSyncSaleOut(1,"XOUT464382", "2025-01-01 23:59:59", "2025-01-02 23:59:59");
        //syncSaleOut.startSyncSaleOut(2,"", "2025-02-10 23:59:59", "2025-02-27 23:59:59");

        // 3552175308069507
        //syncSaleOut.calcCostPrice(3552175308069507L);
    }

    /**
     * 开始同步销售出库
     * @param syncType 同步类型 1: 初始化全量同步  2: 后续定期增量同步 (只有定时同步入参2，其他入参1)
     * @param icstockbillNo
     * @return
     */
    public ResultVo startSyncSaleOut(int syncType, String icstockbillNo, String propStartDate, String propEndDate) {
        try {
            LOGGER.debug(LOGGER_MSG + "处理开始");
            LOGGER.debug(LOGGER_MSG + "propStartDate = " + propStartDate);
            LOGGER.debug(LOGGER_MSG + "propEndDate = " + propEndDate);

            // 从数据配置表中获取数据
            SyncConfig__c syncConfig = getSyncConfig("K3_XXCK");
            String startDate = syncConfig.getAttribute("startDate");
            String endDate = syncConfig.getAttribute("endDate");
            if (StringUtils.isNotBlank(propStartDate) && StringUtils.isNotBlank(propEndDate)) {
                startDate = propStartDate;
                endDate = propEndDate;
            }

            // 设置参数
            Map<String, Object> paramsMap = new HashMap<>();
            paramsMap.put("page", "1");
            paramsMap.put("pageSize", "3000");
            paramsMap.put("customerType", "DM"); // 获取内容类型区分
            // 销售销售出库编号如果不为空 则只查询单条数据
            if (StringUtils.isNotBlank(icstockbillNo)) {
                paramsMap.put("icstockbillNo", icstockbillNo);
            } else {
                // 后续增量同步使用  updateStartDate updateEndDate
                paramsMap.put(syncType == 2 ? "updateStartDate" : "StartDate", startDate); // StartDate EndDate
                paramsMap.put(syncType == 2 ? "updateEndDate" : "EndDate", endDate);
            }
            LOGGER.debug(LOGGER_MSG + " paramsMap: " + paramsMap);

            // 发送请求获取数据
            ResultBody response = EdanK3Utils.sendGet(paramsMap, EdanK3Utils.GET_SALES_OUT_URL, "");
            if (!Objects.equals(response.getCode(), "200")) {
                LOGGER.debug(LOGGER_MSG + "查询k3数据异常: " + response.getMessage());
                return ResultVo.error("查询k3数据异常: " + response.getMessage());
            }

            // 获取数据 判断是否有值
            JSONObject result = (JSONObject) response.getResult();
            List<JSONObject> k3SearchData = JSONObject.parseArray(result.getJSONArray("ICStockInfos").toJSONString(), JSONObject.class);

            LOGGER.debug(LOGGER_MSG + "查询返回的数据: " + k3SearchData.size());
            if (k3SearchData.size() <= 0) {
                LOGGER.debug(LOGGER_MSG + "暂无需要处理的数据");
                // 同步修改配置表
                if (syncType == 2) upSyncConfig(syncConfig);
                return ResultVo.success("暂无需要处理的数据");
            }

            // 按照单号进行分组 fdeleteDate
            List<JSONObject> k3DataList = new ArrayList<>();
            Set<String> k3DelBillNo = new HashSet<>();
            Set<String> productSet = new HashSet<>();
            k3SearchData.stream().forEach(v -> {
                productSet.add("'" + v.getString("fnumber") + "'");
                productSet.add("'" + v.getString("ffpkNumber") + "'");
                if ( StringUtils.isNotBlank(v.getString("fdeleteDate"))) {
                    k3DelBillNo.add("'" + v.getString("fbillNo") + "'");
                } else {
                    k3DataList.add(v);
                }
            });

            Map<String, List<JSONObject>> salOutListMap = k3DataList.stream().collect(Collectors.groupingBy(e -> e.getString("fbillNo")));
            LOGGER.debug(LOGGER_MSG + "salOutListMap: " + salOutListMap.size());

            // 先处理删除的数据
            delSaleOutByNo(StringUtils.join(k3DelBillNo, ","));

            // 获取系统中存在的销售出库
            Map<String, Long> crmSalOutMap = getCrmDataMap("saleOut", "fbillNo", k3DataList);

            // 获取系统中的销售出库明细 (明细标识：主表id + 明细序号)
            String filterVals = k3DataList.stream().map(v -> "'" + v.getString("finterID") + v.getString("fentryID") + "'").collect(Collectors.joining(","));
            String sql = String.format("select id,edanId__c from salesOutReceiptDetails__c where edanId__c in (%s)", filterVals);
            Map<String, Long> crmOutDetailMap = xoqlService.query(sql).getRecords().stream().collect(Collectors.toMap(e -> e.getString("edanId__c"), e1 -> e1.getLong("id")));
            LOGGER.debug(LOGGER_MSG + "crmOutDetailMap: " + crmOutDetailMap);

            // 获取系统中的客户
            Map<String, Long> crmAccountMap = getCrmDataMap("account", "customerCode", k3DataList);

            // 根据k3的订单code获取系统中的订单
            Map<String, Long> crmOrderMap = getCrmDataMap("k3CodeOrder", "orderBillNo", k3DataList);

            // 订单明细
            Map<String, Long> crmOrderDetailMap = getCrmDataMap("orderProductById", "crmOrderDetailID", k3DataList);

            // 获取业务员 以及业务员对应的部门编码
            String names = k3DataList.stream().map(v -> "'" + v.getString("salesman") + "'").distinct().collect(Collectors.joining(","));
            sql = String.format("select id,name,dimDepart,departmentCode__c from user where name in (%s)", StringUtils.isNotBlank(names) ? names + ",'孙睦乔'" : "'孙睦乔'");
            Map<String, JSONObject> crmUserMap = xoqlService.query(sql).getRecords().stream().collect(Collectors.toMap(e -> e.getString("name"), e1 -> e1, (e, e1) -> e));

            // 获取系统中的产品对象 ffpkNumber
            //String productNos = k3DataList.stream().map(v -> "'" + v.getString("fnumber") + "'").distinct().collect(Collectors.joining(","));
            String productNos = StringUtils.join(productSet, ",");
            sql = String.format("select id,productName,FNumber__c,productLine__c,proxyProducts__c,FModel__c,F_105__c from product where FNumber__c in (%s)", productNos);
            List<JSONObject> crmProductList = HCXObjectService.queryAllUseXoql(sql);
            Map<String, JSONObject> crmProductMap = crmProductList.stream().collect(Collectors.toMap(e -> e.getString("FNumber__c"), e1 -> e1, (e, e1) -> e));

            // 获取系统中的部门 且 去除后缀
            String departs = k3DataList.stream().map(v -> {
                String department = v.getString("department");
                if (StringUtils.isNotBlank(department)) {
                    department = department.replace("-POCT", "");
                    v.put("department", department);
                    return "'" +department + "'";
                }
                return null;
            }).distinct().collect(Collectors.joining(","));
            sql = String.format("select id,departName,parentDepartId.departName parentDepartName from department where departName in (%s)", departs);
            Map<String, JSONObject> crmDepartMap = xoqlService.query(sql).getRecords().stream().collect(Collectors.toMap(e -> e.getString("departName"), e1 -> e1, (e, e1) -> e));

            // 根据产品从【博识成本明细表】模块获取近一年的成本
            Map<Long, Double> crmCostMap = new HashMap<>();
            if (crmProductList.size() > 0) {
                long endTimeLong = System.currentTimeMillis();
                long startTimeLong = HCDateUtils.addDaysToLong(endTimeLong, -365);
                String productIds = crmProductList.stream().map(v -> v.getString("id")).collect(Collectors.joining(","));
                sql = String.format("select productName__c, sum(totalCost__c) / sum(quantity__c) as avg  from costDetail__c " +
                        " where productName__c.proxyProducts__c = 16 and productName__c in (%s) and date__c between %s and %s group by productName__c ", productIds, startTimeLong, endTimeLong);
                crmCostMap = xoqlService.query(sql).getRecords().stream().collect(Collectors.toMap(e -> e.getLong("productName__c"), e1 -> e1.getDouble("avg"), (e, e1) -> e));
            }

            // 获取外挂表:【部门-岗位关系】
            sql = "select id,name,productLine__c,customItem3__c,customItem4__c,departmentName__c from positionRelationship__c ";
            List<JSONObject> positionRelationList = HCXObjectService.queryAllUseXoql(sql);


            // 获取外挂表:【用户-职级关系】
            sql = "select id,name,userName__c,job__c,userName__c,customItem11__c,customItem12__c,customItem13__c,customItem14__c,userLevel__c from userRankRelation__c";
            List<UserRankRelation__c> userRankRelationList = HCXObjectService.queryAll(sql);

            // 获取新增、修改的数据
            List<ShippingPersonnelSheet__c> addBscDetail = new ArrayList<>(); // 新增 办事处确认业务员 子表
            List<SalesOutReceipt__c> upMasterList = new ArrayList<>(); // 修改主表
            List<SalesOutReceipt__c> upMasterFieldList = new ArrayList<>(); // 修改主表特殊字段
            List<SalesOutReceiptDetails__c> upDetailList = new ArrayList<>(); // 修改详情
            for (String fbillNo : salOutListMap.keySet()) {
                // 明细数据
                List<JSONObject> detailList = salOutListMap.get(fbillNo);
                if (detailList.size() <= 0) continue;


                // 处理出库
                JSONObject masterObj = detailList.get(0); // 出库数据
                String department = masterObj.getString("department");
                // 2025-04 排查原部门是客户服务部、销售部的数据
                if (Arrays.asList("客户服务部", "销售部").contains(department)) {
                    LOGGER.info(LOGGER_MSG + "排查原部门是客户服务部、销售部的数据 " + fbillNo);
                    continue;
                }

                String finterID = masterObj.getString("finterID");

                SalesOutReceipt__c salesOutReceipt = new SalesOutReceipt__c();
                salesOutReceipt.setEntityType(3533372968819303L);
                salesOutReceipt.setEdanId__c(finterID);
                salesOutReceipt.setName(fbillNo); // 编号
                salesOutReceipt.setDateOfPush__c(getDateVal(masterObj.getString("fdate"), 1)); // 日期

                salesOutReceipt.setCustomerName__c(crmAccountMap.get(masterObj.getString("customerCode"))); // 客户名称 （关联关系）
                salesOutReceipt.setCustomerCode__c(masterObj.getString("customerCode")); // 客户代码
                salesOutReceipt.setAttribute("customerNameText__c", masterObj.getString("customer")); // 客户名称
                salesOutReceipt.setDeliveryAddress__c(masterObj.getString("address")); // 收货地址
                salesOutReceipt.setConsignee__c(masterObj.getString("consignee")); // 收货人
                salesOutReceipt.setConsigneePhone__c(masterObj.getString("tel")); // 收货电话
                salesOutReceipt.setContractCodes__c(masterObj.getString("contractNumber")); // 合同编号
                salesOutReceipt.setOrderNumText__c(masterObj.getString("orderBillNo")); // 订单编号
                salesOutReceipt.setOrderNum__c(crmOrderMap.get(masterObj.getString("orderBillNo"))); // 关联订单
                salesOutReceipt.setContractDate__c(getDateVal(masterObj.getString("contractDate"), 2)); // 合同签订日期
                salesOutReceipt.setBillingDate__c(getDateVal(masterObj.getString("seOrderDate"), 2)); // 开单日期
                salesOutReceipt.setDeliveryDate__c(getDateVal(masterObj.getString("fdate"), 1)); // 发货日期
                salesOutReceipt.setDocumenter__c(masterObj.getString("biller")); // 制单人
                salesOutReceipt.setAbstract__c(masterObj.getString("explanation")); // 摘要

                // 部门
                salesOutReceipt.setOriDepartment__c(department); // 原部门
                if (crmDepartMap.containsKey(department)) {
                    JSONObject departData = crmDepartMap.get(department);
                    salesOutReceipt.setActualSector__c(departData.getLong("id"));  // 实际部门

                    // 大区 (取父级部门)
                    String regionVal = departData.getString("parentDepartName");
                    if (StringUtils.isNotBlank(regionVal) && regionVal.length() > 2) {
                        regionVal = regionVal.replace("区", "");
                    }
                    if (department.equals("OEM")) {
                        regionVal = "销售部";
                    } else if (department.equals("大项目部")) {
                        regionVal = "大项目部";
                    } else if (department.equals("业务发展部")) {
                        regionVal = "民营";
                    }
                    salesOutReceipt.setRegion__c(regionVal);
                }

                // 数据来源
                String dataSources = masterObj.getString("dataSources");
                salesOutReceipt.setDataSource__c(StringUtils.isNotBlank(dataSources) ? dataSources : "k3同步");
                if (StringUtils.isNotBlank(dataSources) && (dataSources.contains("理邦仪器") || dataSources.contains("理邦实验"))) {
                    salesOutReceipt.setVariousDataSources__c(dataSources.contains("理邦仪器") ? 1: 2); // 各类数据源
                }

                // 业务员
                JSONObject salesmanUser = crmUserMap.get(masterObj.getString("salesman"));
                // 2025-03-14 新加逻辑：默认赋值 孙睦乔
                if (salesmanUser == null) salesmanUser = crmUserMap.get("孙睦乔");
                if (salesmanUser != null) {
                    // 业务员
                    salesOutReceipt.setAttribute("salesmanText__c", masterObj.getString("salesman")); // 实际业务员名称
                    salesOutReceipt.setSalesman__c(salesmanUser.getLong("id"));
                    salesOutReceipt.setConfirmingClerk__c(salesmanUser.getLong("id"));

                    // 各类数据源- 判断是否是客服 (判断部门是否是 '客户服务部')
                    Long dimDepart = salesmanUser.getLong("dimDepart");
                    boolean flag = StringUtils.isNotBlank(dataSources) && (dataSources.contains("理邦仪器") || dataSources.contains("理邦实验"));
                    if (Arrays.asList(3351254903184040L, 3351255696169601L).contains(dimDepart) && flag) {
                        salesOutReceipt.setVariousDataSources__c(dataSources.contains("理邦仪器") ? 4: 5); // 各类数据源
                    }
                }

                // 判断系统中是否存在，存在则更新
                System.out.println("salesOutReceipt = " + salesOutReceipt);
                if (crmSalOutMap.containsKey(fbillNo)) {
                    salesOutReceipt.setId(crmSalOutMap.get(fbillNo));
                    upMasterList.add(salesOutReceipt);
                    // 进行更新
                    if (upMasterList.size() >= 50) {
                        HCXObjectService.updateBatch(upMasterList);
                        upMasterList.clear();
                    }
                } else {
                    // 新增
                    OperateResult insert = HCXObjectService.insert(salesOutReceipt);
                    if (!insert.getSuccess()) {
                        LOGGER.error(LOGGER_MSG + "新增出库失败 fbillNo: " + fbillNo);
                        continue;
                    }
                    salesOutReceipt.setId(insert.getDataId());
                }

                // 处理明细数据 (不考虑k3后续同步删除订单明细的情况)
                for (JSONObject detailObj : detailList) {

                    String fentryID = detailObj.getString("fentryID");
                    String edanId = finterID + fentryID; // 唯一标识: finterID + fentryID

                    // 明细对象
                    SalesOutReceiptDetails__c salesOutDetails = new SalesOutReceiptDetails__c();
                    salesOutDetails.setEntityType(3533380753562179L);
                    salesOutDetails.setEdanId__c(edanId); // 数据id
                    salesOutDetails.setName(fbillNo + "-" + fentryID); // 编号
                    salesOutDetails.setSalesOutReceipt__c(salesOutReceipt.getId()); // 主表
                    salesOutDetails.setCorrespondingInvoiceNum__c(detailObj.getString("ffpkName")); // 发票库对应码
                    salesOutDetails.setCorrespondingInvoiceNumCode__c(detailObj.getString("ffpkNumber")); // 发票库对应代码
                    salesOutDetails.setQuantity__c(detailObj.getDouble("fqty")); // 数量
                    salesOutDetails.setPrice__c(detailObj.getDouble("fprice")); // 价格
                    salesOutDetails.setAmount__c(detailObj.getDouble("famount")); // 金额
                    salesOutDetails.setNoTaxCostUnitPrice__c(detailObj.getDouble("unitCost")); // 成本单价
                    salesOutDetails.setQuantity__c(detailObj.getDouble("fqty")); // 数量
                    salesOutDetails.setOrderDetail__c(crmOrderDetailMap.get(detailObj.getString("crmOrderDetailID"))); // 订单明细

                    // 产品
                    JSONObject product = crmProductMap.get(detailObj.getString("fnumber"));
                    Double costUnitPrice = 0.0; // 不含税成本单价
                    int costAttr = 1; // 成本归属 1：理邦  2：博识
                    if (product != null) {
                        salesOutDetails.setPorductName__c(product.getLong("id")); // 产品名称
                        salesOutDetails.setProductCode__c(product.getInteger("productLine__c")); // 产品线-实际 (CRM)
                        salesOutDetails.setProductLine__c(product.getInteger("F_105__c")); // 产品线-实际 (ERP)
                        salesOutDetails.setMonitoringModule__c(getMonitoringId(product)); // 判断监护模块取值

                        // 成本
                        costUnitPrice = crmCostMap.get(product.getLong("id"));
                        if (costUnitPrice != null) {
                            costAttr = 2;
                        }
                    }
                    salesOutDetails.setNoTaxCostUnitPrice__c(costUnitPrice);
                    salesOutDetails.setCostAttribution__c(costAttr);

                    // 发票库产品
                    JSONObject productFp = crmProductMap.get(detailObj.getString("ffpkNumber"));
                    if (productFp != null) {
                        salesOutDetails.setAttribute("productLineFp__c", productFp.getInteger("productLine__c")); // 发票库产品线
                        salesOutDetails.setAttribute("productModelFp__c", productFp.getString("FModel__c")); // 发票库产品型号
                    }

                    // 判断是新增还是修改
                    if (crmOutDetailMap.containsKey(edanId)) {
                        salesOutDetails.setId(crmOutDetailMap.get(edanId));
                        upDetailList.add(salesOutDetails);
                    } else {
                        // 避免繁琐操作，单条新增
                        OperateResult detailInsert = HCXObjectService.insert(salesOutDetails);
                        Long detailId = detailInsert.getDataId();

                        // 处理 出库相关人员报表
                        if (salesmanUser != null) {
                            // 1、实际部门-出库单实际部门
                            // 2、超声/检验报单企业微信审批流程编号-出库单“超声/检验报单企业微信审批流程编号”
                            // 3、划分比例-默认100%
                            // 4、数量-默认出库单明细数量
                            ShippingPersonnelSheet__c addSheet = new ShippingPersonnelSheet__c();
                            addSheet.setEntityType(3533390342314578L);
                            Long salesmanUserId = salesmanUser.getLong("id");
                            addSheet.setCustomItem25__c(salesmanUserId); // 办事处确认业务员
                            addSheet.setSalesOutReceipt__c(salesOutReceipt.getId()); // 出库
                            addSheet.setSalesOutReceiptDetails__c(detailId); // 出库明细
                            addSheet.setNumber__c(detailObj.getDouble("fqty")); // 数量
                            addSheet.setMaterialNum__c(detailObj.getDouble("fqty")); // 耗材数量
                            addSheet.setShiJiBuMen__c(salesOutReceipt.getActualSector__c()); // 实际部门
                            addSheet.setSplitRatio__c(1); // 划分比例
                            addSheet.setYeJiJinE__c(detailObj.getDouble("famount")); // 划分金额

                            // 计算报表字段
                            Long actualSector = salesOutReceipt.getActualSector__c();
                            Map<Integer, JSONObject> positionRelationMap = positionRelationList.stream().filter(v -> Objects.equals(v.getLong("departmentName__c"), actualSector))
                                    .collect(Collectors.toMap(e -> e.getInteger("productLine__c"), e1 -> e1, (e, e1) -> e));
                            UserRankRelation__c userRankRelation = userRankRelationList.stream().filter(v -> Objects.equals(v.getUserName__c(), salesmanUserId)).findFirst().orElse(null);
                            // 更新 是否兽用 1:是 2:否
                            Integer isAnimaluse = CalcSalesOutField.getIsAnimalUse(salesmanUser.getString("departmentCode__c"), product != null ? product.getIntValue("proxyProducts__c") : 0);
                            // 是否为业务发展部业绩
                            Integer isYwfzbyj = CalcSalesOutField.getBusinessDepart(department, salesmanUser.getString("departmentCode__c"));
                            CalcSalesOutField.dealCalcField(addSheet, positionRelationMap, userRankRelation, salesOutDetails.getProductCode__c(), "", actualSector, isYwfzbyj, isAnimaluse);
                            addBscDetail.add(addSheet);
                        }
                    }
                }

                // 进行新增、编辑操作
                if (upDetailList.size() > 50) {
                    HCXObjectService.updateBatch(upDetailList);
                    upDetailList.clear();
                }
                if (addBscDetail.size() > 50) {
                    HCXObjectService.insertBatch(addBscDetail);
                    addBscDetail.clear();
                }
            }

            // 进行批量、新增更新
            HCXObjectService.updateBatch(upMasterList);
            HCXObjectService.updateBatch(upMasterFieldList);
            HCXObjectService.updateBatch(upDetailList);
            HCXObjectService.insertBatch(addBscDetail);

            // 更新同步配置
            if (syncType == 2) upSyncConfig(syncConfig);

            LOGGER.debug(LOGGER_MSG + "处理成功");
            return ResultVo.success("处理成功");
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.debug(LOGGER_MSG + "处理异常:" + e.getMessage());
            return ResultVo.error("处理异常: " + e.getMessage());
        }
    }

     public void delSaleOutByNo(String k3DelBillNo) throws ApiEntityServiceException {
        LOGGER.debug(LOGGER_MSG + " k3DelBillNo = " + k3DelBillNo);
        if (StringUtils.isBlank(k3DelBillNo)) {
            LOGGER.debug(LOGGER_MSG + " 没有需要删除的出库数据");
            return;
        }

        // 获取出库 id
        String sql = String.format("select id from salesOutReceipt__c where name in (%s)", k3DelBillNo);
        List<JSONObject> masterList = xoqlService.query(sql).getRecords();
        String masterIds = masterList.stream().map(v -> v.getString("id")).collect(Collectors.joining(","));

         // 删除出货相关人员表
         sql = String.format("select id from shippingPersonnelSheet__c where salesOutReceipt__c in (%s)", masterIds);
         List<JSONObject> sheetList = xoqlService.query(sql).getRecords();
         List<ShippingPersonnelSheet__c> delSheetList = sheetList.stream().map(v -> {
             ShippingPersonnelSheet__c delSheet = new ShippingPersonnelSheet__c();
             delSheet.setId(v.getLong("id"));
             return delSheet;
         }).collect(Collectors.toList());
         HCXObjectService.deleteBatch(delSheetList);

         // 删除出库表
         List<SalesOutReceipt__c> delSalesOutList = masterList.stream().map(v -> {
             SalesOutReceipt__c delSalesOut = new SalesOutReceipt__c();
             delSalesOut.setId(v.getLong("id"));
             return delSalesOut;
         }).collect(Collectors.toList());
         HCXObjectService.deleteBatch(delSalesOutList);
     }

    /**
     * 获取 监护模块 值
     * @param product
     * @return
     */
    public Long getMonitoringId(JSONObject product) {
        String productName = product.getString("productName");
        String productModel = product.getString("FModel__c");
        Long monitoringId = null;

        // 如果规格型号为空 判断产品名称取值
        if (StringUtils.isBlank(productModel) || productModel.equals("-") || productModel.equals("/")) {
            if (productName.indexOf("V-C.O") != -1) {
                monitoringId = 3543733822200389L; // 型号 - V-C.O
            } else if (productName.indexOf("Draeger AG插件模块整机") != -1) {
                monitoringId = 3543733822200396L; // 名称 - 麻醉气体
            }
            return monitoringId;
        }

        // 规格型号包括 NIBP 直接返回 null
        if (productModel.indexOf("NIBP") != -1) {
            return monitoringId;
        }

        // 根据蓝图上的逻辑进行判断规格型号取值
        if (productModel.indexOf("Nellcor血氧") != -1) {
            monitoringId = 3543733822200387L; // 型号 - 血氧
        } else if (productModel.indexOf("BIS插件模块主机") != -1) {
            // *BIS插件模块主机*
            monitoringId = 3543733822200388L; // 型号 - v-BIS
        } else if (productModel.indexOf("CO2") != -1 && productModel.indexOf("伟康") != -1 && productModel.indexOf("IBP") != -1) {
            // *IBP*&*伟康*&*CO2
            monitoringId = 3543733822200391L; // 型号 - V-IBP,进口呼末CO2
        } else if (productModel.indexOf("CO2") != -1 && productModel.indexOf("IBP") != -1 && productModel.indexOf("伟康") == -1) {
            // *IBP*&*co2*,不含伟康
            monitoringId = 3543733822200393L; // 型号 - V-IBP,理邦呼末CO2
        } else if (productModel.indexOf("CO2") != -1 && productModel.indexOf("伟康") != -1 && productModel.indexOf("IBP") == -1) {
            // *CO2&*伟康*&不含IBP
            monitoringId = 3543733822200390L; // 型号 - 进口呼末CO2
        } else if (productModel.indexOf("IBP") != -1 && productModel.indexOf("CO2") == -1) {
            // *IBP*,不含CO2
            monitoringId = 3543733822200394L; // 型号 - V-IBP
        } else if (productModel.indexOf("PHASEIN") != -1) {
            // *PHASEIN*
            monitoringId = 3543733822200395L; // 型号 - 麻醉气体
        }
        return  monitoringId;
    }






}
